#include "qcrc.h"

QCrc::QCrc(QObject *parent) : QObject(parent)
{

}

// 计算 CRC8
uint8_t QCrc::calculateCRC8(QByteArray &bytes)
{
    // Init: 0x00, Poly: 0x07
    uint8_t *pDat = (uint8_t *)bytes.data();
    int cnt, len = bytes.size();
    uint8_t u8Crc = 0x00;
    uint8_t i;

    for (cnt = 0; cnt < len; cnt++)
    {
        u8Crc ^= *pDat++;
        for (i = 0; i < 8; i++)
        {
            if (u8Crc & 0x80)
            {
                u8Crc = (u8Crc << 1) ^ 0x07;
            }
            else
            {
                u8Crc <<= 1;
            }
        }
    }

    return u8Crc;
}
// 计算 CRC16/Modbus
uint16_t QCrc::calculateCRC16Modbus(QByteArray &bytes)
{
    // Init: 0xffff, Poly: 0x8005
    uint8_t *pDat = (uint8_t *)bytes.data();
    int cnt, len = bytes.size();
    uint16_t u16Crc = 0xffff;
    uint8_t i;

    for (cnt = 0; cnt < len; cnt++)
    {
        u16Crc ^= *pDat++;

        for (i = 0; i < 8; i++)
        {
            if (u16Crc & 0x1)
            {
                u16Crc >>= 1;
                u16Crc ^= 0xa001; // 0x8005 翻转 0xa001
            }
            else
            {
                u16Crc >>= 1;
            }
        }
    }

    return u16Crc;
}
// 计算 CRC16/XModem
uint16_t QCrc::calculateCRC16XModem(QByteArray &bytes)
{
    // Init: 0x0000, Poly: 0x1021
    uint8_t *pDat = (uint8_t *)bytes.data();
    int cnt, len = bytes.size();
    uint16_t u16Crc = 0x0000;
    uint16_t u16Poly = 0x1021;
    uint8_t u8Dat = 0;
    uint8_t i;

    for (cnt = 0; cnt < len; cnt++)
    {
        u8Dat = *pDat++;
        u16Crc ^= (u8Dat << 8);

        for (i = 0; i < 8; i++)
        {
            if (u16Crc & 0x8000)
            {
                u16Crc = (u16Crc << 1) ^ u16Poly;
            }
            else
            {
                u16Crc = u16Crc << 1;
            }
        }
    }

    return u16Crc;
}
// 计算 CRC32
uint32_t QCrc::calculateCRC32(QByteArray &bytes)
{
    uint8_t *pDat = (uint8_t *)bytes.data();
    int cnt, len = bytes.size();
    uint32_t u32Crc = 0xFFFFFFFF;
    uint32_t u32Poly = 0x04C11DB7;
    uint8_t i;
 
    InvertUint32(&u32Poly,&u32Poly);
    for (cnt = 0; cnt < len; cnt++)
    {
        u32Crc ^= *pDat++;
        for (i = 0; i < 8; i++)
        {
            if(u32Crc & 0x1)
                u32Crc = (u32Crc >> 1) ^ u32Poly;
            else
                u32Crc = u32Crc >> 1;
        }
    }

    return (u32Crc ^ 0xFFFFFFFF) ;
}

// private functions

//按位翻转
void QCrc::InvertUint8(uint8_t *out, uint8_t *in)
{
    uint8_t tmp = 0x0;
    uint8_t i;

    for (i = 0; i < 8; i++)
    {
        if (in[0] & (1ul << i))
        {
            tmp |= 1ul << (7 - i);
        }
    }

    out[0] = tmp;
}
//按位翻转，如 0x8005 -> 0xa001
void QCrc::InvertUint16(uint16_t *out, uint16_t *in)
{
    uint16_t tmp = 0x0;
    uint8_t i;

    for (i = 0; i < 16; i++)
    {
        if (in[0] & (1ul << i))
        {
            tmp |= 1ul << (15 - i);
        }
    }

    out[0] = tmp;
}
//按位翻转
void QCrc::InvertUint32(uint32_t *out, uint32_t *in)
{
    uint32_t tmp = 0x0;
    uint8_t i;

    for (i = 0; i < 32; i++)
    {
        if (in[0] & (1ul << i))
        {
            tmp |= 1ul << (31 - i);
        }
    }

    out[0] = tmp;
}
